package com.tian.core.dao.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;

import com.tian.core.bean.PageList;
import com.tian.core.bean.Pages;
import com.tian.core.dao.BaseDAO;


public class BaseDAOImpl<T> implements BaseDAO<T> {

	protected SessionFactory sessionFactory;
	
	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	/*public BaseDAOImpl() {
		this.entityClass = null;
		Class c = getClass();
		Type type = c.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
		}
	}*/
	
	protected Session getSession(){
		return this.sessionFactory.getCurrentSession();
	}
	
	@SuppressWarnings("unchecked")
	public T save(T entity) {
		Integer id = (Integer) getSession().save(entity);
		return (T) get(id,entity.getClass());
	}

	public void delete(T entity) {
		getSession().delete(entity);
	}

	public void delete(Integer id, Class entityClass) {
		T entity= get(id, entityClass);
		getSession().delete(entity);
	}

	public void delete(String[] ids, Class entityClass) {
		for(String id:ids){
			T entity=load(Integer.parseInt(id.trim()), entityClass);
			getSession().delete(entity);
		}
	}
	public boolean isHasChildren(String[] pids, Class entityClass){		
		for(String pid:pids){
			String hql = "select count(*) from " + entityClass.getName() + " as model where model.pid = ? ";
			if((Long) getSession().createQuery(hql).setParameter(0, pid.trim()).uniqueResult()>0){
				return true;
			}
		}
		return false;
	}
	public void update(T entity) {
		getSession().merge(entity);
	}

	@SuppressWarnings("unchecked")
	public T get(Integer id, Class entityClass) {
		return (T)getSession().get(entityClass, id);
	}
	
	@SuppressWarnings("unchecked")
	public T load(Integer id, Class entityClass) {
		return (T)getSession().load(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> getListByHQL(String hql) {
		return getSession().createQuery(hql).list();
	}

	@SuppressWarnings("unchecked")
	public T get(String propertyName, Object value, Class entityClass) {
		String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
		return (T)getSession().createQuery(hql).setParameter(0, value).uniqueResult();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getList(String condition, Class entityClass) {
		String hql = "from " + entityClass.getName() + " as model where 1=1 "+condition;
		return getSession().createQuery(hql).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> getList(String propertyName, Object value, Class entityClass) {
		String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
		return getSession().createQuery(hql).setParameter(0, value).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> getAll(Class entityClass) {
		String hql = "from " + entityClass.getName();
		return getSession().createQuery(hql).list();
	}

	public Long getTotalCount(Class entityClass) {
		String hql = "select count(*) from " + entityClass.getName();
		return (Long) getSession().createQuery(hql).uniqueResult();
	}
	
	public Integer getMax(String propertyName,Class entityClass){
		String hql = "select max(model."+propertyName+") from " + entityClass.getName()+" as model ";
		return (Integer)getSession().createQuery(hql).uniqueResult();
	}
	public boolean isExist(String propertyName, Object value, Class entityClass) {
		T object = get(propertyName, value, entityClass);
		return null!=object;
	}

	public void flush() {
		getSession().flush();
	}

	public void clear() {
		getSession().clear();
	}

	public void evict(Object object) {
		getSession().evict(object);
	}

	public PageList findByPages(Pages pages, Class entityClass) {
		String hql = "from " +  entityClass.getName().substring(entityClass.getName().lastIndexOf(".")+1);
		if(null==pages){
			pages=new Pages();
		}
		if(pages.getTotalNum()==-1){
			String countHql = "select count(*) from " + entityClass.getName().substring(entityClass.getName().lastIndexOf(".")+1);
			int totalNum = Integer.parseInt(getSession().createQuery(countHql).list().get(0).toString());
			pages.setTotalNum(totalNum);
		}
		pages.executeCount();
		List list = getSession().createQuery(hql).setFirstResult(pages.getSpage()).setMaxResults(pages.getPerPageNum()).list();
		PageList pageList = new PageList();
		pageList.setObjectList(list);
		pageList.setPages(pages);
		return pageList;
	}

	public PageList findByPages(Pages pages, DetachedCriteria detachedCriteria) {
		if(null==pages){
			pages=new Pages();
		}
		PageList pageList = new PageList();
		Criteria criteria=detachedCriteria.getExecutableCriteria(getSession());
		if (pages.getTotalNum() == -1) {
			pages.setTotalNum((Long)criteria.setProjection(Projections.rowCount()).uniqueResult());
			criteria.setProjection(null);
		}
		pages.executeCount();
		criteria.setFirstResult(pages.getSpage());
		criteria.setMaxResults(pages.getPerPageNum());
		pageList.setObjectList(criteria.list());
		pageList.setPages(pages);
		return pageList;
	}

	public List getListByDetachedCriteria(DetachedCriteria detachedCriteria) {
		Criteria criteria=detachedCriteria.getExecutableCriteria(getSession());
		criteria.setProjection(null);
		criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
		return criteria.list();
	}
	
	public List getListByIds(String[] ids, Class entityClass){
		String hql = "from " + entityClass.getName() + " as model where model.id in :ids";
		return getSession().createQuery(hql).setParameter("ids", ids).list();
	}

	public List queryHQL(String hql, Map params) {
		Query query=getSession().createQuery(hql);
		if(null!=params){
			Set<String> keys=params.keySet();
			for(String key:keys){
				if(params.get(key) instanceof Collection){
					query.setParameterList(key, (Collection)params.get(key));
				}else{
					query.setParameter(key, params.get(key));
				}
			}
		}
		return query.list();
	}
	
	public PageList queryHQL(String hql, String hqlCount, Map<Integer, String> params, Pages pages) {
		if(null==pages){
			pages=new Pages();
		}
		if(pages.getTotalNum()==-1){
			int totalNum = Integer.parseInt(getSession().createQuery(hqlCount).list().get(0).toString());
			pages.setTotalNum(totalNum);
		}
		pages.executeCount();
		Query query=getSession().createQuery(hql).setFirstResult(pages.getSpage()).setMaxResults(pages.getPerPageNum());
		if(null!=params){
			Set<Integer> keys=params.keySet();
			for(Integer key:keys){
				query.setParameter(key, params.get(key));
			}
		}
		List list = query.list();
		PageList pageList = new PageList();
		pageList.setObjectList(list);
		pageList.setPages(pages);
		return pageList;
	}
	
	public Integer executeHQL(String hql, Map<Integer, String> params) {
		Query query=getSession().createQuery(hql);
		if(null!=params){
			Set<Integer> keys=params.keySet();
			for(Integer key:keys){
				query.setParameter(key, params.get(key));
			}
		}
		return query.executeUpdate();
	}

	public List querySQL(String sql, Map<Integer, String> params){
		SQLQuery query = getSession().createSQLQuery(sql);
		if(null!=params){
			if(null!=params){
				Set<Integer> keys=params.keySet();
				for(Integer key:keys){
					query.setParameter(key, params.get(key));
				}
			}
		}
		return query.list();
	}
}
